package cn.com.shopec.erp.stock.service.impl;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang.StringUtils;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import cn.com.shopec.erp.base.dao.ISupplierInfoDao;
import cn.com.shopec.erp.common.constant.ProductSCMConstant;
import cn.com.shopec.erp.common.constant.SZSCMConstant;
import cn.com.shopec.erp.common.page.PageFinder;
import cn.com.shopec.erp.common.page.PageQuery;
import cn.com.shopec.erp.common.utils.DateUtil;
import cn.com.shopec.erp.common.utils.IntegerUtil;
import cn.com.shopec.erp.common.utils.LongUtil;
import cn.com.shopec.erp.common.utils.StringUtil;
import cn.com.shopec.erp.multiChannel.service.IChannelOrderService;
import cn.com.shopec.erp.product.dao.ICommodityDao;
import cn.com.shopec.erp.product.dao.IProductDao;
import cn.com.shopec.erp.product.dao.IProductStockDao;
import cn.com.shopec.erp.product.entity.ProductStock;
import cn.com.shopec.erp.product.service.IDefectReplceService;
import cn.com.shopec.erp.purchase.entity.StockPurchase;
import cn.com.shopec.erp.purchase.service.IPurchaseReturnOrderService;
import cn.com.shopec.erp.purchase.service.IStockPurchaseService;
import cn.com.shopec.erp.stock.commo.ObjectUtil;
import cn.com.shopec.erp.stock.commo.StockHistroyUtil;
import cn.com.shopec.erp.stock.commo.StockOutUtil;
import cn.com.shopec.erp.stock.commo.StockProductException;
import cn.com.shopec.erp.stock.dao.IProductBarCodeDao;
import cn.com.shopec.erp.stock.dao.IStockHistoryDao;
import cn.com.shopec.erp.stock.dao.IStockOutDao;
import cn.com.shopec.erp.stock.dao.IStockOutProductDao;
import cn.com.shopec.erp.stock.dao.IStockOutPurInfoDao;
import cn.com.shopec.erp.stock.entity.StockHistory;
import cn.com.shopec.erp.stock.entity.StockOut;
import cn.com.shopec.erp.stock.entity.StockOutProduct;
import cn.com.shopec.erp.stock.service.IStockOutService;
import cn.com.shopec.erp.stock.vo.StockOutProductVo;
import cn.com.shopec.erp.stock.vo.StockOutVo;
import cn.com.shopec.erp.system.common.UserUtils;
import cn.com.shopec.erp.warehouse.service.IStockTransferService;

/**
 * @ClassName: StockOutServiceImpl
 * @Description: 出库信息service接口实现类
 * @author: zengxuezhou
 * @date: 2016年11月28日 下午2:30:27
 */
@Service
public class StockOutServiceImpl implements IStockOutService {

	@Resource
	private IProductStockDao productStockDao;

	@Resource
	private IStockOutDao stockOutDao;

	@Resource
	private ICommodityDao commodityDao;

	@Resource
	private IStockOutProductDao stockOutProductDao;

	@Resource
	private IProductDao productDao;

	@Resource
	private ISupplierInfoDao supplierInfoDao;

	@Resource
	private IStockHistoryDao stockHistoryDao;

	@Resource
	private IChannelOrderService channelOrderService;

	@Resource
	private IStockTransferService stockTransferService;

	@Resource
	private IPurchaseReturnOrderService purchaseReturnOrderService;

	@Resource
	private IDefectReplceService defectReplceService;

	@Resource
	private IStockPurchaseService stockPurchaseService;

	@Resource
	private IStockOutPurInfoDao stockOutPurInfoDao;

	@Resource
	private IProductBarCodeDao productBarCodeDao;

	@Override
	public PageFinder<StockOutVo> queryStockList(StockOutVo stockOut, PageQuery pageQuery) {

		PageFinder<StockOut> poageFinder = stockOutDao.pagedByCriteria(getQueryCriteria(stockOut), pageQuery.getPage(),
				pageQuery.getPageSize());
		return getStockOutVoPageFinder(poageFinder);
	}

	@Override
	public List<StockOutVo> queryStockOutListByFinder(StockOutVo stockOut) {
		List<StockOut> list = stockOutDao.findByCriteria(getQueryCriteria(stockOut));
		List<StockOutVo> result = new ArrayList<StockOutVo>();
		if (list != null && list.size() > 0) {
			for (StockOut obj : list) {
				result.add(StockOutUtil.parseStockOutVo(obj));
			}
		}
		return result;
	}

	/**
	 * 设置查询出库信息的条件
	 * 
	 * @param stockOut
	 * @return
	 */
	DetachedCriteria getQueryCriteria(StockOutVo stockOut) {
		DetachedCriteria detachedCriteria = stockOutDao.createCriteria();
		if (StringUtil.isExist(stockOut.getStockOutNo())) {// 出库单编号
			detachedCriteria.add(Restrictions.like("stockOutNo", stockOut.getStockOutNo(), MatchMode.ANYWHERE));
		}
		if (ObjectUtil.isNotNull(stockOut.getStockOutType())) {// 出库单编号
			detachedCriteria.add(Restrictions.eq("stockOutType", stockOut.getStockOutType()));
		}
		if (StringUtil.isExist(stockOut.getBeginTime())) {// 出库起始时间
			detachedCriteria.add(Restrictions.ge("createTime", DateUtil.parseTimesTampDate(stockOut.getBeginTime())));
		}
		if (StringUtil.isExist(stockOut.getEndTime())) {// 出库结束时间
			detachedCriteria.add(Restrictions.le("createTime", DateUtil.parseTimesTampDate(stockOut.getEndTime())));
		}
		detachedCriteria.add(Restrictions.eq("deletedFlag", SZSCMConstant.DELETE_FLAG_NO));
		detachedCriteria.addOrder(Order.desc("createTime"));
		return detachedCriteria;
	}

	/**
	 * 根据PageFinder<StockOut>拼装PageFinder<StockOutVo>
	 * 
	 * @param pageFinders
	 * @return
	 */
	private PageFinder<StockOutVo> getStockOutVoPageFinder(PageFinder<StockOut> pageFinders) {

		List<StockOutVo> stockOutVos = new ArrayList<StockOutVo>();
		List<StockOut> stockOuts = pageFinders.getData();
		for (StockOut stockOut : stockOuts) {
			StockOutVo stockOutVo = StockOutUtil.parseStockOutVo(stockOut);
			stockOutVos.add(stockOutVo);
		}
		PageFinder<StockOutVo> result = new PageFinder<StockOutVo>(pageFinders.getPageNo(), pageFinders.getPageSize(),
				pageFinders.getRowCount());
		result.setData(stockOutVos);
		return result;
	}

	@Override
	public PageFinder<StockOutProductVo> queryStockProductList(StockOutVo stockOut, PageQuery pageQuery) {
		int count = stockOutProductDao.getProductsCountByStockNo(stockOut.getStockOutNo());
		PageFinder<StockOutProductVo> result = new PageFinder<StockOutProductVo>(pageQuery.getPage(),
				pageQuery.getPageSize(), count);
		if (IntegerUtil.gtZero(count)) {
			List<StockOutProductVo> stockOutVos = stockOutProductDao.getProductsListByStockNo(stockOut.getStockOutNo(),
					result.getStartOfPage(), result.getPageSize());
			result.setData(stockOutVos);
		}
		return result;
	}

	@Override
	public PageFinder<StockOutProductVo> queryStockProductListForTransfer(String stockInTypeNo, PageQuery pageQuery) {
		StockOut stockOut = stockOutDao.get("stockOutTypeNo", stockInTypeNo);
		PageFinder<StockOutProductVo> result = null;
		if (ObjectUtil.isNotNull(stockOut)) {
			int count = stockOutProductDao.getProductsCountByStockNo(stockOut.getStockOutNo());
			result = new PageFinder<StockOutProductVo>(pageQuery.getPage(), pageQuery.getPageSize(), count);
			if (IntegerUtil.gtZero(count)) {
				List<StockOutProductVo> stockOutVos = stockOutProductDao.getProductsListByStockNo(
						stockOut.getStockOutNo(), result.getStartOfPage(), result.getPageSize());
				result.setData(stockOutVos);
			}
		}
		return result;
	}

	@Override
	public StockOutVo getStockByNo(String stockOutNo) {
		StockOut stockOut = stockOutDao.get("stockOutNo", stockOutNo);
		StockOutVo stockOutVo = StockOutUtil.parseStockOutVo(stockOut);
		return stockOutVo;
	}

	@Override
	@Transactional
	public boolean addStockOut(StockOut stockOut, List<StockOutProduct> stockOutProducts) throws Exception {
		if (ObjectUtil.isNotNull(stockOut)) {
			addStock(stockOut);
			addStockOutProduct(stockOut.getStockOutNo(), stockOutProducts);
			if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_1)) {
				channelOrderService.updateProductPactkageState(stockOut.getStockOutTypeNo(), 1);
			} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_2)) {
				purchaseReturnOrderService.updateAuditResultPurchaseOrder(stockOut.getStockOutTypeNo(),
						ProductSCMConstant.PURCHASERETURN_STATUS_TWO);
			} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_3)) {
				defectReplceService.updateAuditResultDefectReplce(stockOut.getStockOutTypeNo(),
						ProductSCMConstant.DEFECTREPLCE_STATE_1);
			} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_4)) {
				channelOrderService.updateProductPackageReturnState(stockOut.getStockOutTypeNo(),
						SZSCMConstant.CHANNEL_ORDER_RETURN_STATE_5);// 改变订单退货状态
			} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_5)) {
				stockTransferService.setStockOutFlowState(stockOut.getStockOutTypeNo());
			}
			return true;
		}
		return false;
	}

	@Override
	@Transactional
	public void approveStockOut(StockOutVo stockOutVo, List<StockOutProduct> stockOutProducts) throws Exception {
		StockOut stockOut = stockOutDao.get("stockOutNo", stockOutVo.getStockOutNo());
		// StockOut stockOut = stockOutDao.getById(stockOutVo.getId());//
		// 查询出库单基础信息
		DetachedCriteria criteria = stockOutProductDao.createCriteria();

		stockOut.setProductFetchType(stockOutVo.getProductFetchType());
		if (stockOutVo.getProductFetchType().equals(SZSCMConstant.PRODUCT_FETCH_TYPE_2)) {
			stockOut.setLogisticsName(stockOutVo.getLogisticsName());
			stockOut.setLogisticsNo(stockOutVo.getLogisticsNo());
			stockOut.setLogisticsOrder(stockOutVo.getLogisticsOrder());
		}

		criteria.add(Restrictions.eq("stockOutNo", stockOut.getStockOutNo()));
		// List<StockOutProduct> stockOutProducts =
		// stockOutProductDao.findByCriteria(criteria);// 查询出库单产品信息
		beginApproveStockOut(stockOut, stockOutProducts);

	}

	@Override
	@Transactional
	public void approveStockOut(String stockOutId, List<StockOutProduct> stockOutProducts) throws Exception {
		StockOut stockOut = stockOutDao.getById(stockOutId);// 查询出库单基础信息
		// updateStockOutProduct(stockOut.getStockOutNo(), stockOutProducts);
		beginApproveStockOut(stockOut, stockOutProducts);
	}

	/**
	 * 开始正式出库（出库审核）
	 * 
	 * @param stockOut
	 * @param stockOutProducts
	 * @return
	 * @throws Exception
	 */
	@Transactional
	private void beginApproveStockOut(StockOut stockOut, List<StockOutProduct> stockOutProducts) throws Exception {
		if (ObjectUtil.isNotNull(stockOut) && ObjectUtil.ne(stockOut.getStockOutState(), SZSCMConstant.STOCK_STATE_YES)
				&& ObjectUtil.eq(stockOut.getDeletedFlag(), SZSCMConstant.DELETE_FLAG_NO)) {// 判断是否为有效信息

			if (!CollectionUtils.isEmpty(stockOutProducts)) {// 判断出库单是否拥有产品

				stockOut.setStockOutState(SZSCMConstant.STOCK_STATE_YES);
				stockOut.setUpdater(UserUtils.getLoginUserName());
				stockOut.setUpdateTime(DateUtil.parseSqlDate(DateUtil.getCurrentDate()));
				stockOutDao.update(stockOut);// 修改出库单状态为:'已出库'

				for (StockOutProduct stockOutProduct : stockOutProducts) {

					long nowProductTotal = changeProductStockForStockOut(stockOut, stockOutProduct);// 减少库存

					StockHistory stockHistory = StockHistroyUtil.parseStockHistory(stockOut, stockOutProduct,
							nowProductTotal);// 修改仓库变更记录
					stockHistoryDao.save(stockHistory);
					stockOutProductDao.update(stockOutProduct);
				}
				updateRelatedBillStateForAdd(stockOut);// 修改相关单据信息
			}
		}
	}

	/**
	 * 修改相关单据信息
	 * 
	 * @param stockOut
	 * @throws Exception
	 */
	@Transactional
	private void updateRelatedBillStateForAdd(StockOut stockOut) throws Exception {
		if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_1)) {
			channelOrderService.updateProductPactkageState(stockOut.getStockOutTypeNo(), 2);// 修改包裹单出库状态
		} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_4)) {
			channelOrderService.updateProductPackageReturnState(stockOut.getStockOutTypeNo(),
					SZSCMConstant.CHANNEL_ORDER_RETURN_STATE_2);// 改变订单退货状态
		} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_2)) {
			purchaseReturnOrderService.updateAuditResultPurchaseOrder(stockOut.getStockOutTypeNo(),
					ProductSCMConstant.PURCHASERETURN_STATUS_THREE);// 修改采购单出库状态
		} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_3)) {// 次品退货出库状态
			defectReplceService.updateAuditResultDefectReplce(stockOut.getStockOutTypeNo(),
					ProductSCMConstant.DEFECTREPLCE_STATE_2);
		} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_5)) {// 次品退货出库状态
			stockTransferService.setStockOutFinishFlowState(stockOut.getStockOutTypeNo());
		}
	}

	/**
	 * 出库，返回数据库存储的数据对象
	 * 
	 * @param productStock
	 * @return
	 * @throws Exception
	 */
	@Transactional
	private long changeProductStockForStockOut(StockOut stockOut, StockOutProduct stockOutProduct) throws Exception {
		ProductStock productStockFromDB = productStockDao
				.findUniqueProduct(StockOutUtil.parseProductStock(stockOut, stockOutProduct));
		long stockoutQuantity = LongUtil.valuesOf(stockOutProduct.getStockoutQuantity());
		if (ObjectUtil.isNull(productStockFromDB) || stockoutQuantity < 1) { // 获取的数据存在，并且出库数量不能少于1件
			throw new StockProductException(stockOutProduct, productStockFromDB);
		}
		boolean result = false;
		if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_1)) {// 包裹单出库
			updateStockPurChaseByPur(stockOut, stockOutProduct);
			result = productStockDao.changeQuantity(productStockFromDB.getId(), stockoutQuantity, stockoutQuantity, 0L);
		} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_2)) {// 采购单退货出库(仅良品)
			updateStockPurchase(stockOutProduct, stockoutQuantity, 0L);// 维护商品采购关系表
			result = productStockDao.changeQuantity(productStockFromDB.getId(), stockoutQuantity, 0L, 0L);
		} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_3)) {// 次品退货出库
			updateStockPurchase(stockOutProduct, 0L, stockoutQuantity);
			result = productStockDao.changeQuantity(productStockFromDB.getId(), 0L, 0L, stockoutQuantity);
		} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_4)) {// 订单退换货出库
			updateStockPurChaseByPur(stockOut, stockOutProduct);
			result = productStockDao.changeQuantity(productStockFromDB.getId(), stockoutQuantity, 0L, 0L);
		} else if (ObjectUtil.eq(stockOut.getStockOutType(), SZSCMConstant.STOCKOUT_TYPE_5)) {// 调拨退货出库
			updateStockPurChaseByPur(stockOut, stockOutProduct);
			result = productStockDao.changeQuantity(productStockFromDB.getId(), stockoutQuantity, 0L, 0L);
		}
		if (result) {
			return productStockFromDB.getProductTotal() - stockoutQuantity;
		}
		throw new StockProductException(stockOutProduct, productStockFromDB);
	}

	@Transactional
	private void updateStockPurChaseByPur(StockOut stockOut, StockOutProduct stockOutProduct) throws Exception {
		List<Object[]> stockOutPurInfoVos = null;
		if (ObjectUtil.eq(stockOutProduct.getProductCodeState(), SZSCMConstant.PRODUCT_PUR_STATE_1)) {
			stockOutPurInfoVos = productBarCodeDao.queryForStockOut(stockOutProduct.getId());
		} else if (ObjectUtil.eq(stockOutProduct.getProductCodeState(), SZSCMConstant.PRODUCT_PUR_STATE_2)) {
			stockOutPurInfoVos = stockOutPurInfoDao.queryForStockOut(stockOutProduct.getId());
		}

		if (CollectionUtils.isEmpty(stockOutPurInfoVos)) {
			throw new StockProductException(stockOutProduct, stockOutPurInfoVos);
		}
		StockOutProduct temp = new StockOutProduct();
		temp.setWhNo(stockOutProduct.getWhNo());
		temp.setProdNo(stockOutProduct.getProdNo());
		for (Object[] objects : stockOutPurInfoVos) {
			temp.setPurNo(objects[0].toString());
			updateStockPurchase(temp, ObjectUtil.toLong(objects[1]), 0L);// 维护商品采购关系表
		}
	}

	/**
	 * 维护采购库存关系表
	 * 
	 * @param stockOutProduct
	 * @param qualifiedQuantity
	 * @param defectiveQuantity
	 * @throws Exception
	 */
	@Transactional
	private void updateStockPurchase(StockOutProduct stockOutProduct, Long qualifiedQuantity, Long defectiveQuantity)
			throws Exception {
		StockPurchase stockPurchase = new StockPurchase();
		stockPurchase.setPoNo(stockOutProduct.getPurNo());
		stockPurchase.setProdNo(stockOutProduct.getProdNo());
		stockPurchase.setWhNo(stockOutProduct.getWhNo());
		stockPurchase.setYieldAmountNumner(-qualifiedQuantity);
		stockPurchase.setDefectiveAmountNumber(-defectiveQuantity);
		if (stockPurchaseService.changeQuantity(stockPurchase) == false) {
			throw new StockProductException(stockOutProduct, stockPurchase);
		}
	}

	/**
	 * 只增加出库基础信息
	 * 
	 * @param stockOut
	 * @throws Exception
	 */
	@Transactional
	private void addStock(StockOut stockOut) throws Exception {
		stockOut.setDeletedFlag(SZSCMConstant.DELETE_FLAG_NO);
		stockOut.setStockOutState(SZSCMConstant.STOCK_STATE_NO);
		stockOut.setCreater(UserUtils.getLoginUserName());
		stockOut.setCreateTime(DateUtil.parseSqlDate(DateUtil.getCurrentDate()));
		stockOutDao.save(stockOut);
	}

	/**
	 * 增加出库信息中的商品
	 * 
	 * @param stockOutProduct
	 * @throws Exception
	 */
	@Transactional
	private void addStockOutProduct(StockOutProduct stockOutProduct) throws Exception {
		if (ObjectUtil.isNotNull(stockOutProduct)) {
			stockOutProduct.setId(null);
			stockOutProduct.setCreater(UserUtils.getLoginUserName());
			stockOutProduct.setCreateTime(DateUtil.parseSqlDate(DateUtil.getCurrentDate()));
			stockOutProduct.setDeletedFlag(SZSCMConstant.DELETE_FLAG_NO);
			stockOutProductDao.save(stockOutProduct);
		}
	}

	/**
	 * 批量增加出库信息中的商品
	 * 
	 * @param stockOutNo
	 * @param stockOutProducts
	 * @return
	 * @throws Exception
	 */
	@Transactional
	private boolean addStockOutProduct(String stockOutNo, List<StockOutProduct> stockOutProducts) throws Exception {
		if (StringUtils.isNotEmpty(stockOutNo) && !CollectionUtils.isEmpty(stockOutProducts)) {
			for (StockOutProduct stockOutProduct : stockOutProducts) {
				stockOutProduct.setStockOutNo(stockOutNo);
				addStockOutProduct(stockOutProduct);
			}
			return true;
		}
		return false;
	}

	/**
	 * 修改出库信息中的商品
	 * 
	 * @param stockOutNo
	 * @param stockOutProducts
	 * @return
	 * @throws Exception
	 */
	@Transactional
	private boolean updateStockOutProduct(String stockOutNo, List<StockOutProduct> stockOutProducts) throws Exception {
		boolean isRemove = stockOutProductDao.removeForUpdate(stockOutNo);
		if (isRemove) {
			return addStockOutProduct(stockOutNo, stockOutProducts);
		}
		return false;
	}

	/**
	 * 只删除出库信息
	 */
	@Override
	@Transactional
	public boolean deleteStockOut(String stockOutNo) throws Exception {
		if (StringUtils.isNotEmpty(stockOutNo)) {
			StockOut stockOut = stockOutDao.get("stockOutNo", stockOutNo);
			if (ObjectUtil.isNotNull(stockOut)) {
				stockOut.setDeletedFlag(SZSCMConstant.DELETE_FLAG_YES);
				stockOutDao.update(stockOut);
				stockOutProductDao.removeProductByStockOutNo(stockOutNo);
			}
			return true;
		}
		return false;
	}

	/**
	 * 删除出库商品
	 */
	@Override
	public boolean deleteStockOutProduct(String id) throws Exception {
		if (StringUtils.isNotEmpty(id)) {
			StockOutProduct stockOut = stockOutProductDao.get("id", id);
			if (ObjectUtil.isNotNull(stockOut)) {
				stockOut.setDeletedFlag(SZSCMConstant.DELETE_FLAG_YES);
				stockOutProductDao.update(stockOut);
				return true;
			}
		}
		return false;
	}

}
